package im.composer.midi.seq;

import im.composer.vapu.VAPU;

import javax.sound.midi.InvalidMidiDataException;
import javax.sound.midi.MidiMessage;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
import javax.sound.midi.Sequence;

import org.jaudiolibs.audioservers.AudioConfiguration;

import themidibus.listener.StandardMidiListener;

public class SequencerAdapter extends VAPU implements StandardMidiListener {

	protected final VirtualSequencer vseq = new VirtualSequencer();
	protected transient long start_frame_num;

	public SequencerAdapter() {
		super();
	}

	public SequencerAdapter(AudioConfiguration context) {
		super(context);
	}

	public void open() throws MidiUnavailableException {
		vseq.open();
	}

	public boolean isOpen() {
		return vseq.isOpen();
	}

	public boolean isFinished() {
		if(isRecording()||!isRunning()){
			return false;
		}
		long len = vseq.getMicrosecondLength();
		if(len==0){
			return false;
		}
		return vseq.getMicrosecondPosition() >= vseq.getMicrosecondLength();
	}

	public void setSequence(Sequence sequence) throws InvalidMidiDataException {
		vseq.setSequence(sequence);
	}

	public Sequence getSequence() {
		return vseq.getSequence();
	}

	@Override
	public void midiMessage(MidiMessage message, long timeStamp) {
		vseq.send(message, timeStamp);
	}

	public long getRecordPosition() {
		return vseq.getRecordPosition();
	}

	public void setRecordPosition(long recordPosition) {
		vseq.setRecordPosition(recordPosition);
	}

	@Override
	public Receiver getReceiver() {
		return vseq.getTransmitter().getReceiver();
	}

	@Override
	public void setReceiver(Receiver receiver) {
		vseq.getTransmitter().setReceiver(receiver);
	}

	public void start() {
		vseq.start();
		start_frame_num = getTime();
	}

	public void stop() {
		vseq.stop();
	}

	public boolean isRunning() {
		return vseq.isRunning();
	}

	@Override
	public void close() {
		vseq.close();
	}

	public void startRecording() {
		super.startRecording();
		vseq.startRecording();
	}

	public void stopRecording() {
		super.stopRecording();
		vseq.stopRecording();
	}

	public boolean isRecording() {
		return vseq.isRecording();
	}

	public Sequence getRecordedSequence() {
		return vseq.getRecordedSequence();
	}

	@Override
	public synchronized void resetTime(long t) {
		super.resetTime(t);
		if (isRunning()) {
			stop();
			start_frame_num = t;
			start();
		} else {
			start_frame_num = t;
		}
	}

	@Override
	protected void computeBuffer() {
		long pos = (long) ((getTime() - start_frame_num) * millisecond_per_frame * 1000d);
		vseq.setMicrosecondPosition(pos);
		vseq.run();
	}

	@Override
	public void executeCommand(long timeStamp, String command) {
	}

}
